package AliDiepPR.ANN;

import AliDiepPR.ANN.BackPropagation;
import AliDiepPR.ANN.Network;
import AliDiepPR.ANN.NeuralNetworkException;
import AliDiepPR.ANN.ActivationFunction.IActivationFunction;

public class Learn {

	BackPropagation back;

	Network net;

	public Network Network(Network net, boolean set) {
		if (set)
			this.Network(net, set);
		return net;
	}

	public double Rate(double rate, boolean set) {
		if (set)
			back.Rate(rate, true);
		return back.rate;
	}

	public IActivationFunction ActivationFunc(IActivationFunction func,
			boolean set) {
		if (set)
			back.ActivationFunc(func, set);
		return back.func;
	}

	public Learn(double rate, IActivationFunction func) {
		back = new BackPropagation(rate, func);
	}

	public Learn(Network net, double rate, IActivationFunction func) {
		back = new BackPropagation(rate, func);
		this.net = net;
	}

	public void LearnBackpropagation(double[][] input, double[][] output) throws NeuralNetworkException{
		if (input[0].length != net.layer[0].numUnit)
			throw new NeuralNetworkException("Input is invalid!");

		back.Epoch(this.net, input, output);
	}

	public double GradientError(double[][] input, double[][] output) {
		double error = 0;
		int m = input.length;

		for (int i = 0; i < m; i++) {
			back.Forward(net, input[i]);
			for (int j = 0; j < output[0].length; j++)
				error += (double) Math
						.pow((double) (output[i][j] - net.layer[net.numLayer - 1].unit[j].output),
								(double) 2);
		}

		return error;
	}

	public double[] Test(Network net, double[] input) {
		back.Forward(net, input);
		return net.layer[net.numLayer - 1].Output();
	}
}
